package ga;
/**
 * MasterMindOperadoresGeneticos, implementa: <br>
 * 1.- Cruza <br>
 * 2.- Mutacion Circular <br>
 * 3.- Transposicion <br>
 * 4.- Hipermutacion <br>
 * @author Roberto Loaeza Valerio
 *
 */
public class MasterMindOperadoresGeneticos extends MasterMindBase{
	/**
	 * Devuelve el siguiente color 
	 * @param color Color actual
	 * @return Colo siguiente
	 */
	private char sigColor(char color) {
		return  color==colores[colores.length-1]?'0':(char)(color+1);
	}
	
	/**
	 * Mutacion Circular
	 * @param individuo Id del individuo
	 * @return El mismo individuo con un cromosoma mutado
	 */
	public char[] mutacionCircular(int individuo) {
		char[] ret = clone(getIndividuo(individuo));
		int x = r.nextInt(L);
		ret[x] = sigColor(ret[x]);
		return ret;
	}
	
	/**
	 * Intercambia P[a] por P[b]
	 * @param P Arreglo P
	 * @param a posicion a
	 * @param b posicion b
	 */
	private void swap(char[] P, int a, int b) {
		char t = P[a];
		P[a] = P[b];
		P[b] = t;
	}
	
	/**
	 * Tranposicion
	 * @param individuo Id del individuo
	 * @return Un nuevo individuo con su contenido transpuesto
	 */
	public char[] transposicion(int individuo) {
		char[] ret = clone(getIndividuo(individuo));
		for(int i=0; i<L; i++)
			swap(ret, i, r.nextInt(L));			
		return ret;
	}
	
	/**
	 * CrossOver A con B
	 * @param A Padre A
	 * @param B Padre B
	 * @param pi inicio del rango
	 * @param pj fin del rango
	 * @return Un hijo con [A0, A1, ... Api] + [Api+1, Api+2, ... Apj] + [Apj+1, Apj+2, ... An]
	 */
	private char[] crossOver(char[] A, char[] B, int pi, int pj) {
		char[] ret = new char[A.length];
		for(int i=0; i<ret.length; i++) 
			ret[i] = ( (i>=pi)&&(i<=pj))?B[i]:A[i];
		return ret;
	}
	
	/**
	 * Cruza dos padres
	 * @param A Padre A
	 * @param B Padre B
	 * @return 2 Hijos con caracteristicas de sus padres
	 */
	public char[][] cruza(int A, int B) {				
		int r1 = r.nextInt(L/2);
		int r2 = (L/2)+r.nextInt(L/2);		
		r2= (r1+r2)==L?r2-1:r2;		
		return new char[][] {crossOver(getIndividuo(A), getIndividuo(B), r1, r2), 
				             crossOver(getIndividuo(B), getIndividuo(A), r1, r2)};		
	}
	
	/**
	 * Crea una nueva poblacion (elimina la actual)
	 */
	public void hiperMutacion() {
		crearPoblacion(nPob);
	}
	
	/**
	 * Muta la mitad de la poblacion con los porcentajes definidos en las variables
	 * nC(crossover), nT(transposicion), nM(mutacion circular).
	 */	
	public void Mutar() {
		int n = (nPob/2);
		double[] prob = {
                nC/100,     /* crossover*/
                nT/100,     /* transposition */
                nM/100      /* circular mutation */
		};
				
		char r[][] = new char[2][];
		for(int i=0; i<n;i++ ) {		
			if(i<(prob[0]*n)) {	
				r = cruza(i, i+1);
				setIndividuo(nPob-i-1, r[0]);
				setIndividuo(nPob-(++i)-1, r[1]);
				
			}
			else if(i<(prob[0]*n)+(prob[1]*n))
				setIndividuo(nPob-i-1, transposicion(i));
			else 
				setIndividuo(nPob-i-1, mutacionCircular(i));					
		}		
		
	}
	
	
	
	
	
	public MasterMindOperadoresGeneticos() {
		super();
	}
	
	/**
	 * Crea una instancia de MasterMindOperadoresGenticos 
	 * @param np # de poblacion
	 * @param nj # maximo de jugadas
	 * @param nh # de generaciones antes de hipermutacion
	 * @param nc % de cruza
	 * @param nt % de transposicion
	 * @param nm % de mutacion circular
	 * @param nr # de hipermutaciones antes de game over
	 */
	public MasterMindOperadoresGeneticos(int np, int nj, int nh, int nc, int nt, int nm, int nr) {
		super(np, nj, nh, nc, nt, nm, nr);
		
	}
}
